<script setup lang="ts">
import { invoke } from '@tauri-apps/api/core';
import { listen, UnlistenFn } from '@tauri-apps/api/event';
import { computed, onMounted, onUnmounted, ref } from 'vue';
import { useI18n } from 'vue-i18n';

import HomeContent from '@/features/home/components/HomeContent.vue';
import HomeFooter from '@/features/home/components/HomeFooter.vue';
import HomeHeader from '@/features/home/components/HomeHeader.vue';
import AnalysisParameter from '@/features/home/models/analysis-parameter';
import DuplicationAnalysisResult from '@/features/home/models/duplication-analysis-result';

const { t } = useI18n();
const secondInMilliseconds = 1000;
const minuteInMilliseconds = secondInMilliseconds * 60;
const hourInMilliseconds = minuteInMilliseconds * 60;
const formatNumber = new Intl.NumberFormat();
const analysisResult = ref<DuplicationAnalysisResult>();
const processing = ref(false);
const statusInfo = ref('');

const duplicateFileCount = computed(() =>
  analysisResult.value?.duplicateFiles
    ? Object.keys(analysisResult.value.duplicateFiles).length
    : 0,
);

// Listener of analysis-in-progress and will be unlistened in unmounted phase.
let unlistenAnalysisInProgressFn: UnlistenFn;

onMounted(() => {
  // Sets up listener for analysis-in-progress.
  listenOnAnalysisInProgress();
});

onUnmounted(() => {
  // Unlistens for analysis-in-progress.
  unlistenAnalysisInProgressFn?.();
});

/**
 * Creates listener on analysis-in-progress.
 */
async function listenOnAnalysisInProgress(): Promise<void> {
  unlistenAnalysisInProgressFn = await listen<string>('analysis-in-progress', (event) => {
    if (processing) {
      statusInfo.value = `${t('analyzing')} ${event.payload}`;
    }
  });
}

/**
 * Formats elapsed time to friendly format.
 */
function formatElapsedTime(elapsedTime: number): string {
  let calculatedElapsedTime = elapsedTime;
  let denominator = 1;
  let unitType: string;

  if (elapsedTime < secondInMilliseconds) {
    unitType = 'ms';
  } else if (elapsedTime < minuteInMilliseconds) {
    denominator = secondInMilliseconds;
    unitType = 'sec';
  } else if (elapsedTime < hourInMilliseconds) {
    denominator = minuteInMilliseconds;
    unitType = 'min';
  } else {
    denominator = hourInMilliseconds;
    unitType = 'hour';
  }

  // Calculates the output elapsed time by denominator.
  calculatedElapsedTime = elapsedTime / denominator;

  // Fixes the decimal part to zero to display only whole numbers.
  const fixedCalculatedElapsedTime = parseFloat(calculatedElapsedTime.toFixed(0));

  // Formats the output elapsed time with the specified number of decimal places.
  return `${formatNumber.format(fixedCalculatedElapsedTime)} ${unitType}`;
}

/**
 * Starts processing and displays info.
 */
async function startProcessing(param: AnalysisParameter): Promise<void> {
  if (param) {
    processing.value = true;
    analysisResult.value = new DuplicationAnalysisResult();
    const startTime = performance.now();

    try {
      const result: DuplicationAnalysisResult = await invoke('search_duplicate_file', {
        param: param,
      });

      analysisResult.value = result;
    } finally {
      if (processing.value) {
        processing.value = false;
        const elapsedTime = performance.now() - startTime;

        statusInfo.value = t('duplicateResult', {
          duplicateFileCount: formatNumber.format(duplicateFileCount.value),
          totalFilesCount: formatNumber.format(analysisResult.value?.totalFilesCount),
          elapsedTime: formatElapsedTime(elapsedTime),
        });
      }
    }
  }
}

/**
 * Cancels current processing.
 */
async function cancelProcessing(): Promise<void> {
  processing.value = false;
  await invoke('cancel_processing', { canceled: true });
  statusInfo.value = t('processingCanceled');
}
</script>

<template>
  <div class="main-container">
    <header>
      <HomeHeader
        :processing
        @start-processing="startProcessing"
        @cancel-processing="cancelProcessing"
      />
    </header>
    <HomeContent :processing :analysisResult :duplicateFileCount />
    <footer>
      <HomeFooter :statusInfo />
    </footer>
  </div>
</template>

<style scoped>
.main-container {
  display: flex;
  flex-direction: column;
  height: 100vh;
}

header {
  position: sticky;
  top: 0px;
  z-index: 99;
}
</style>
